From 2b982798afc5a3184851cdecc87d12511b58746d Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 28 Feb 2008 10:45:47 +0000 Subject: [PATCH] kexec: limit scope of the use of compat_kexec_range_t Unless I am mistaken, the compat functions are provided a stable ABI. This includes providing a stable version of xen_kexec_range_t in the form of compat_kexec_range_t. However, internally it doesn't really matter how xen represents the data. Currently the code provides for the creation of a compat version of all kexec range functions, which use the compat_kexec_range_t function. This is difficult to extend if range code exists outside of xen/common/kexec.c. The existence of "#ifdef CONFIG_X86_64" in the code suggests that some of the range code might be better off in architecture specific code. Furthermore, subsequent patches will introduce ia64-specific range handling code, which really would be much better off somewhere in arch/ia64/. With this in mind, the handling of compat_kexec_range_t is changed such that the code which reads and returns data from user-space translates between compat_kexec_range_t and xen_kexec_range_t. As, padding aside, the two structures are currently the same this is quite easy. Things may get more tricky in the future, but I don't believe this change is likely to make things significantly worse (or better) in that regard. In any case, refactoring can occur again as required. Signed-off-by: Simon Horman --- xen/common/compat/kexec.c | 5 --- xen/common/kexec.c | 79 ++++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/xen/common/compat/kexec.c b/xen/common/compat/kexec.c index b167d8a4ff..bcf9d05908 100644 --- a/xen/common/compat/kexec.c +++ b/xen/common/compat/kexec.c @@ -9,11 +9,6 @@ #define do_kexec_op compat_kexec_op -#undef kexec_get -#define kexec_get(x) compat_kexec_get_##x -#define xen_kexec_range compat_kexec_range -#define xen_kexec_range_t compat_kexec_range_t - #define kexec_load_unload compat_kexec_load_unload #define xen_kexec_load compat_kexec_load #define xen_kexec_load_t compat_kexec_load_t diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 4e95cf319d..f1aa784e93 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -153,11 +153,7 @@ static int sizeof_note(const char *name, int descsz) ELFNOTE_ALIGN(descsz)); } -#define kexec_get(x) kexec_get_##x - -#endif - -static int kexec_get(reserve)(xen_kexec_range_t *range) +static int kexec_get_reserve(xen_kexec_range_t *range) { if ( kexec_crash_area.size > 0 && kexec_crash_area.start > 0) { range->start = kexec_crash_area.start; @@ -168,7 +164,7 @@ static int kexec_get(reserve)(xen_kexec_range_t *range) return 0; } -static int kexec_get(xen)(xen_kexec_range_t *range) +static int kexec_get_xen(xen_kexec_range_t *range) { #ifdef CONFIG_X86_64 range->start = xenheap_phys_start; @@ -179,7 +175,7 @@ static int kexec_get(xen)(xen_kexec_range_t *range) return 0; } -static int kexec_get(cpu)(xen_kexec_range_t *range) +static int kexec_get_cpu(xen_kexec_range_t *range) { int nr = range->nr; int nr_bytes = 0; @@ -223,33 +219,78 @@ static int kexec_get(cpu)(xen_kexec_range_t *range) return 0; } -static int kexec_get(range)(XEN_GUEST_HANDLE(void) uarg) +static int kexec_get_range_internal(xen_kexec_range_t *range) { - xen_kexec_range_t range; int ret = -EINVAL; - if ( unlikely(copy_from_guest(&range, uarg, 1)) ) - return -EFAULT; - - switch ( range.range ) + switch ( range->range ) { case KEXEC_RANGE_MA_CRASH: - ret = kexec_get(reserve)(&range); + ret = kexec_get_reserve(range); break; case KEXEC_RANGE_MA_XEN: - ret = kexec_get(xen)(&range); + ret = kexec_get_xen(range); break; case KEXEC_RANGE_MA_CPU: - ret = kexec_get(cpu)(&range); + ret = kexec_get_cpu(range); break; } + return ret; +} + +static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_range_t range; + int ret = -EINVAL; + + if ( unlikely(copy_from_guest(&range, uarg, 1)) ) + return -EFAULT; + + ret = kexec_get_range_internal(&range); + if ( ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)) ) return -EFAULT; return ret; } +#else /* COMPAT */ + +#ifdef CONFIG_COMPAT +static int kexec_get_range_compat(XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_range_t range; + compat_kexec_range_t compat_range; + int ret = -EINVAL; + + if ( unlikely(copy_from_guest(&compat_range, uarg, 1)) ) + return -EFAULT; + + range.range = compat_range.range; + range.nr = compat_range.nr; + range.size = compat_range.size; + range.start = compat_range.start; + + ret = kexec_get_range_internal(&range); + + if ( ret == 0 ) { + range.range = compat_range.range; + range.nr = compat_range.nr; + range.size = compat_range.size; + range.start = compat_range.start; + + if ( unlikely(copy_to_guest(uarg, &compat_range, 1)) ) + return -EFAULT; + } + + return ret; +} +#endif /* CONFIG_COMPAT */ + +#endif /* COMPAT */ + + #ifndef COMPAT static int kexec_load_get_bits(int type, int *base, int *bit) @@ -375,7 +416,11 @@ ret_t do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) switch ( op ) { case KEXEC_CMD_kexec_get_range: - ret = kexec_get(range)(uarg); +#ifndef COMPAT + ret = kexec_get_range(uarg); +#else + ret = kexec_get_range_compat(uarg); +#endif break; case KEXEC_CMD_kexec_load: case KEXEC_CMD_kexec_unload: -- 2.30.2